{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### pry-docの読み込み\n",
    "#require \"/root/git_jupyter_notebook/Ruby/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "require \"/Users/ftakao2007/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# ライブラリ\n",
    "\n",
    "* 組み込みライブラリ\n",
    "    * requireしなくても使える\n",
    "* 標準添付ライブラリ\n",
    "    * requireしないと使えない\n",
    "\n",
    "# ライブラリを読み込む構文\n",
    "\n",
    "* require\n",
    "    * 1回だけ読み込む\n",
    "        * すでに読み込まれている場合、以降読み込もうとするとfalseを返す\n",
    "    * 相対PATHや絶対PATHで指定\n",
    "    * 拡張子の「.rb」は省略可能\n",
    "* load\n",
    "    * 毎回無条件に読み込む\n",
    "        * pry等でライブラリのデバッグしているときに読み込むときなどに使う\n",
    "        * 拡張子の「.rb」は省略できない\n",
    "* require_relative\n",
    "    * 自身のファイルが存在するディレクトリを起点に読み込む\n",
    "    * 拡張子の「.rb」は省略可能\n",
    "\n",
    "\n",
    "## 添付ライブラリの分類\n",
    "\n",
    "* テキスト\n",
    "    * メッセージダイジェスト暗号化やテンプレートエンジンなど、文字列の加工や入出力を行う\n",
    "    * digest, erb, stringioなど\n",
    "* ファイルフォーマット\n",
    "    * yaml, json, rexml, rss, zlib, csvなど\n",
    "* ファイル\n",
    "    * ファイルシステムの操作をOSに依存しない形で提供するライブラリ\n",
    "    * fileutils, find, pathnameなど\n",
    "* ネットワーク\n",
    "    * 単純な通信ソケットの管理やインターネット上でよく使われるプロトコルを扱う\n",
    "    * socket, open-uri, uri, net/http, net/ftp, net/pop, net/smtpなど\n",
    "* 入出力\n",
    "    * IOクラスの拡張ライブラリや外部プログラムの標準入出力を制御するライブラリ\n",
    "    * io/nonblack, io/wait, open3など\n",
    "* 文字コード\n",
    "    * 各種文字コードのエンコーディングを変換するライブラリ\n",
    "    * kconv, nkfなど\n",
    "* 数学\n",
    "    * 行列や精度の高い少数点数を扱うためのライブラリ\n",
    "    * matrix, mathn, bigdecimalなど\n",
    "* データベース\n",
    "    * Dbmと呼ばれるデータベースを扱うためのライブラリ\n",
    "    * dbm, gdbm, sdbm, pstoreなど\n",
    "* CUI\n",
    "    * cursesやreadlineなど端末上での画面制御を行うためのライブラリ\n",
    "    * readlineなど\n",
    "* 日付・時間\n",
    "    * 日付・時間を扱うライブラリ\n",
    "    * date, timeなど\n",
    "* スレッド\n",
    "    * スレッドの排他処理、同期処理を管理するライブラリ\n",
    "    * thread, sync, mutex_m\n",
    "* UNIX\n",
    "    * UNIXパスワードファイルの管理やsyslogへの書き出しを管理するライブラリ\n",
    "    * etc, syslog\n",
    "* Windows\n",
    "    * Windows APIへのアクセスやレジストリへのアクセス手段を提供する\n",
    "    * Win32API, Win32OLE\n",
    "* デザインパターン\n",
    "    * デザインパターンによる設計を支援するライブラリ\n",
    "    * delegate, observer, singletonなど\n",
    "* 開発\n",
    "    * ユニットテストライブラリやデバッガ、プロファイラなど開発を支援するライブラリ\n",
    "    * test/unit, minitest, rake, pp, benchmark, profiler, mkmfなど\n",
    "* コマンドライン\n",
    "    * オプション付きのプログラムを書くための、プログラムの行数のパースを支援するライブラリ\n",
    "    * optparser, getoptiongなど"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## テキスト\n",
    "\n",
    "* ライブラリ\n",
    "    * StringIO\n",
    "        * 文字列をIOオブジェクトのように扱うことができる\n",
    "    * digest\n",
    "        * 文字列のハッシュ化を行う\n",
    "    * erb\n",
    "        * テンプレートに基づいて出力する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[StringIO, IO::generic_writable, IO::generic_readable, Enumerable, Data, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "StringIO.ancestors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# thread (マルチスレッドプログラミング)\n",
    "\n",
    "* 組み込みライブラリ以外に標準添付ライブラリも有る\n",
    "    * Queue(キュー)や状態変数を使えるようになる\n",
    "\n",
    "## Queue\n",
    "\n",
    "* スレッドセーフ(複数のスレッドから同時にアクセスしても壊れない)なFIFOキュー\n",
    "* pushやpop(もしくはenqやdeq)メソッドが有る\n",
    "    * Arrayを利用する感覚で使える\n",
    "* キューにデータが無いときにpopを呼ぶと新しいキューにデータが入るまで呼び出し元はブロックされる\n",
    "    * かんたんにワーカースレッドを実装できる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "require 'thread'\n",
    "\n",
    "queue = Queue.new\n",
    "\n",
    "## # ワーカースレッドを３つ用意\n",
    "workers = 3.times.map {|t|\n",
    "  Thread.fork {\n",
    "    while req = queue.deq\n",
    "      puts \"Worker#{t} processing..\"\n",
    "      req.call\n",
    "    end\n",
    "  }\n",
    "}\n",
    "\n",
    "\n",
    "## # 10個のリクエストをenqueueする\n",
    "10.times do |t|\n",
    "  queue.enq -> {\n",
    "    sleep 1 # 何らかの処理\n",
    "  }\n",
    "end\n",
    "\n",
    "## # 全てのキューが処理されるまで待つ\n",
    "p \"wait1\"\n",
    "sleep 1 until queue.empty?\n",
    "\n",
    "## # キューが空になったので全てのthreadがキューを待っている\n",
    "p \"workers.map\"\n",
    "p workers.map(&:status)\n",
    "\n",
    "## # 再度キューに追加\n",
    "3.times do |t|\n",
    "  queue.enq -> {\n",
    "    sleep 1 # 何らかの処理\n",
    "  }\n",
    "end\n",
    "\n",
    "## # キューを処理している最中の状態を表示\n",
    "p workers.map(&:status)\n",
    "\n",
    "## # 全てのキューが処理されるまで待つ\n",
    "p \"wait2\"\n",
    "sleep 1 until queue.empty?\n",
    "\n",
    "### 他にSizedQueueという引数にサイズの上限を指定できるものもある\n",
    "\n",
    "## ConditionVariable\n",
    "### (以下今の段階では省略)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# yaml\n",
    "\n",
    "* 構造化されたデータをプレーンな文字列で表現するためのデータ形式のひとつ\n",
    "* XMLよりも読みやすく書きやすい\n",
    "* インデントでハッシュの構造を表現する\n",
    "* YAMLで表現できるデータ型\n",
    "    * 文字列\n",
    "    * 整数\n",
    "    * 浮動小数点\n",
    "    * 真偽値\n",
    "    * nil\n",
    "    * 配列\n",
    "    * ハッシュ\n",
    "* YAMLはバックエンドにPsychと呼ばれるモジュールを利用している\n",
    "    * Ruby1.9まではSyckを利用していた\n",
    "    * SyckはYAMLバージョン1.0、Psychはバージョン1.1を扱うことができる\n",
    "        * 古いYAMLをどうしても読み込む必要がある場合はSyckを使う\n",
    "        * gem instllしてから requireする必要がある\n",
    "        * Ruby1.9からOBSOLETEになっている。普通は使わない。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"localhost\"\n",
      "{\"remote\"=>{\"host\"=>\"example.com\", \"port\"=>22, \"ssh\"=>true, \"username\"=>\"user\", \"password\"=>\"pass\"}}\n",
      "{\"remote\"=>{\"host\"=>\"example2.com\", \"port\"=>22, \"ssh\"=>true, \"username\"=>\"user\", \"password\"=>\"pass\"}}\n",
      "\"---\\nremote:\\n  host: example2.com\\n  port: 22\\n  ssh: true\\n  username: user\\n  password: pass\\n\"\n",
      "\"---\\nremote:\\n  host: example2.com\\n  port: 22\\n  ssh: true\\n  username: user\\n  password: pass\\n\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"---\\nremote:\\n  host: example2.com\\n  port: 22\\n  ssh: true\\n  username: user\\n  password: pass\\n\""
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "require 'yaml'\n",
    "\n",
    "#p YAML::ENGINE.yamler\n",
    "\n",
    "yaml_string = <<EOS\n",
    "---\n",
    "remote:\n",
    "  host: localhost\n",
    "  port: 22\n",
    "  ssh: true\n",
    "  username: user\n",
    "  password: pass\n",
    "EOS\n",
    "\n",
    "setting = YAML.load(yaml_string)\n",
    "\n",
    "### hostの値を取り出す\n",
    "p setting['remote']['host']\n",
    "\n",
    "### hostの値を変更する\n",
    "setting['remote'].update('host' => 'example.com')\n",
    "p setting\n",
    "\n",
    "setting['remote']['host'] = 'example2.com'\n",
    "p setting\n",
    "\n",
    "### オブジェクトをYAMLとしてdump\n",
    "p YAML.dump(setting)\n",
    "p setting.to_yaml"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# JSON\n",
    "\n",
    "* jsonで表現できるデータ型\n",
    "    * 文字列\n",
    "    * 整数\n",
    "    * 浮動小数点\n",
    "    * 真偽値\n",
    "    * nil\n",
    "    * ハッシュ\n",
    "    * 配列(?)\n",
    "* これ以外のオブジェクトをJSONにダンプした場合\n",
    "    * to_jsonメソッドが定義されていない場合、to_sメソッドの結果が返される\n",
    "        * Time, Regexp, Object, Range, Symbolなど\n",
    "        * 自分で定義したクラスがハッシュや配列、文字列を継承していない場合でto_sでの結果以外にしたい場合はto_jsonメソッドを上書きする\n",
    "        * YAMLはSymbolがそのまま使えるが、jsonはSymbolに相当する型が無いので文字列に変換される"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2.0, \"\\u5FB3\\u5CF6\", {\"key\"=>\"value\"}, [1, 2], nil, true, false]\n",
      "\"[1,2.0,\\\"\\u5FB3\\u5CF6\\\",{\\\"key\\\":\\\"value\\\"},[1,2],null,true,false]\"\n",
      "[1, 2.0, \"\\u5FB3\\u5CF6\", {\"key\"=>\"value\"}, [1, 2], nil, true, false]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[1, 2.0, \"\\u5FB3\\u5CF6\", {\"key\"=>\"value\"}, [1, 2], nil, true, false]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "require 'json'\n",
    "p data = [1, 2.0, \"徳島\", {\"key\" => \"value\"}, [1,2], nil, true, false]\n",
    "\n",
    "### JSONとしてdump\n",
    "JSON.dump(data)\n",
    "p data.to_json\n",
    "\n",
    "### ロードする\n",
    "json = data.to_json\n",
    "p JSON.load(json)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# csv\n",
    "\n",
    "* 2次元の情報をコンマと改行で区切る形式\n",
    "    * Array#to_csvで配列をCSV形式の文字列に変換できる\n",
    "    * String#parse_csvでレシーバの文字列をCSV形式の1行としてparseした結果を返す"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"\\u3059\\u3060\\u3061,\\u3046\\u3069\\u3093,\\u307F\\u304B\\u3093,\\u304B\\u3064\\u304A\\n\"\n",
      "[\"\\u3059\\u3060\\u3061\", \"\\u3046\\u3069\\u3093\", \"\\u307F\\u304B\\u3093\", \"\\u304B\\u3064\\u304A\"]\n",
      "[\"foo\", \"bar\", \"baz\"]\n",
      "[\"\\u5FB3\\u5CF6:\\\"\\u3059\\u3060\\u3061\\\"\", \"\\u9999\\u5DDD:\\\"\\u3046\\u3069\\u3093\\\"\"]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[\"\\u5FB3\\u5CF6:\\\"\\u3059\\u3060\\u3061\\\"\", \"\\u9999\\u5DDD:\\\"\\u3046\\u3069\\u3093\\\"\"]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "require 'csv'\n",
    "### 配列をcsvに変換\n",
    "p csv = [\"すだち\", \"うどん\", \"みかん\", \"かつお\"].to_csv\n",
    "\n",
    "### csvを配列に変換\n",
    "p csv.parse_csv\n",
    "\n",
    "### フィールドはダブルクオートで囲んでも囲まなくても処理できる\n",
    "p %(foo,\"bar\",baz).parse_csv\n",
    "\n",
    "### 明示的にダブルクオートを含めたい場合はダブルクオートでエスケープし、かつフィールド全体をダブルクオートで囲む\n",
    "p %(\"徳島:\"\"すだち\"\"\",\"香川:\"\"うどん\"\"\").parse_csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "* 複数行のCSVをparse\n",
    "    * CSV.new\n",
    "        * CSVの文字列を渡すとCSVオブジェクトを得ることができる\n",
    "        * Enumerableモジュールをインクルードしており、行を要素とした配列、すなわち二次元配列のように扱える\n",
    "        * 行を表す要素はデフォルトでは各フィールドを要素とする配列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<#CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\">\n",
      "[\"foo\", \"bar\", \"baz\"]\n",
      "[\"hoge\", \"fuga\", \"haga\"]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "require 'csv'\n",
    "\n",
    "csv = CSV.new(<<EOF)\n",
    "foo,bar,baz\n",
    "hoge,fuga,haga\n",
    "EOF\n",
    "\n",
    "p csv\n",
    "\n",
    "csv.each do |row|\n",
    "  p row\n",
    "  #puts row.join(\"|\")\n",
    "end\n",
    "print \"\\n\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "* CSV.parse\n",
    "    * ブロックを受け取ると各業をブロック引数として順番に実行する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"foo,bar,baz\\nhoge,fuga,haga\\n\"\n",
      "[\"foo\", \"bar\", \"baz\"]\n",
      "[\"hoge\", \"fuga\", \"haga\"]\n"
     ]
    }
   ],
   "source": [
    "require 'csv'\n",
    "\n",
    "data = <<EOF\n",
    "foo,bar,baz\n",
    "hoge,fuga,haga\n",
    "EOF\n",
    "\n",
    "p data\n",
    "\n",
    "CSV.parse(data) do |row|\n",
    "  p row\n",
    "  #puts row\n",
    "  #puts row.join(\"|\")\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "source": [
    "第二引数にハッシュでオプションを渡すことができる\n",
    "\n",
    "|第二引数|オプション|\n",
    "|---|---|\n",
    "|:col_sep|フィールド(列)間のセパレータとして使用する文字列。デフォルトはカンマ|\n",
    "|:row_sep|レコード(行)のセパレータとして使用する文字列。デフォルトは:auto という値|\n",
    "|-|\\n または \\r\\n がセパレータとして利用される|\n",
    "|:quote_char|フィールドを囲む文字。デフォルトはダブルクオート|\n",
    "|:encoding|エンコーディングの指定。|\n",
    "|-|NONE(n or N)、EUC(e or E)、SJIS(s or S)、UTF-8(u or U)|\n",
    "|:converters|フィールドのオブジェクトを変換したい場合にProcオブジェクトかシンボルを指定|\n",
    "|:unconverted_fields|trueにするとCSVをparseした結果のArrayやCSV::Rowにunconverted_fieldsメソッドが追加される|\n",
    "|-|変換前の行を配列で得られる|\n",
    "|:headers|trueまたは:first_rowを指定すると1行目をヘッダとみなす。あるいはヘッダを配列で指定できる|\n",
    "|:return_headers|trueにするとヘッダとみなした1行目もCSVとして読み込む|\n",
    "|:header_converters|ヘッダ専用のコンバータをProcオプションまたはシンボルで指定|\n",
    "|:skip_blanks|trueにすると空行を読み飛ばす|\n",
    "|:force_quotes|trueにするとフィールド生成時に必ずクォートする|\n",
    "|:write_headers|trueかつheadersに値がある場合ヘッダを出力するようになる|"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Ruby 2.3.1",
   "language": "ruby",
   "name": "ruby"
  },
  "language_info": {
   "file_extension": ".rb",
   "mimetype": "application/x-ruby",
   "name": "ruby",
   "version": "2.3.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
